package uz.rt.physics;

import uz.rt.units.Energy;
import uz.rt.units.Length;
import uz.rt.utils.Pair;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

/**
 * The class handles the file input of curve data like PDD's and TPR's
 */
public class CurveFileInputReader
{
// ------------------------------ FIELDS ------------------------------

// -------------------------- OTHER METHODS --------------------------

    public synchronized void readPdd(String filename, Pdd pdd) throws IOException
    {
        File f = new File(filename);
        readPdd(f, pdd);
    }

    public synchronized void readPdd(File file, Pdd pdd) throws IOException
    {
        if (pdd == null) pdd = new Pdd();
        BufferedReader br = new BufferedReader(new FileReader(file));
        String l;
        Length.Unit lu = readPddHeader(br, pdd);
        if (lu == null) throw new IOException("Parsing error: pdd unit can't be null");
        while ((l = br.readLine()) != null)
        {
            if (l.startsWith(CurveIO.commentToken)) continue;
            if (l.trim().equals(System.getProperty("line.separator")) || l.trim().isEmpty()) continue;
            String[] s = l.trim().replaceAll(" ", "").split(",");
            if (s.length != 2) throw new IOException("Parsing error");
            pdd.add(new Pair<Length, Double>(new Length(Double.valueOf(s[0]), lu), Double.valueOf(s[1])));
        }
        br.close();
        pdd.sort();
    }

    private synchronized Length.Unit readPddHeader(BufferedReader br, Pdd pdd) throws IOException
    {
        String l;
        while (((l = br.readLine()).startsWith(CurveIO.commentToken)))
        {
        }
        // read the pdd energy
        if (!l.startsWith("energy:")) throw new IOException("Parsing error: expected energy tag");
        String[] s = l.replaceAll("energy:", "").trim().split(" ");
        if (s.length != 2) throw new IOException("Parsing error: expected energy and its unit separated by a space");
        double value = Double.valueOf(s[0]);
        Energy.Unit unit;
        s[1] = s[1].trim();
        if (s[1].equals("MV")) unit = Energy.Unit.MV;
        else if (s[1].equals("MeV")) unit = Energy.Unit.MeV;
        else throw new IOException("Parsing error: encountered an unknown energy unit tag");
        pdd.setEnergy(new Energy(value, unit));
        // read the unit of the x parameters
        l = br.readLine();
        if (!l.startsWith("unit:")) throw new IOException("Parsing error: expected unit tag");
        l = l.replace("unit:", "").trim();
        if (l.equals("mm")) return Length.Unit.mm;
        else if (l.equals("cm")) return Length.Unit.cm;
        else throw new IOException("Parsing error: encountered an unknown unit tag");
    }

    public synchronized void readTpr(File file, Tpr tpr) throws IOException
    {
        if (tpr == null) tpr = new Tpr();
        BufferedReader br = new BufferedReader(new FileReader(file));
        String l;
        Length.Unit lu = readTprHeader(br, tpr);
        if (lu == null) throw new IOException("Parsing error: tpr unit can't be null");
        while ((l = br.readLine()) != null)
        {
            if (l.startsWith(CurveIO.commentToken)) continue;
            if (l.trim().equals(System.getProperty("line.separator")) || l.trim().isEmpty()) continue;
            String[] s = l.trim().replaceAll(" ", "").split(",");
            if (s.length != 2) throw new IOException("Parsing error");
            tpr.add(new Pair<Length, Double>(new Length(Double.valueOf(s[0]), lu), Double.valueOf(s[1])));
        }
        br.close();
        tpr.sort();
    }

    private synchronized Length.Unit readTprHeader(BufferedReader br, Tpr tpr) throws IOException
    {
        String l;
        while (((l = br.readLine()).startsWith(CurveIO.commentToken)))
        {
        }
        // read the pdd energy
        if (!l.startsWith("energy:")) throw new IOException("Parsing error: expected energy tag");
        String[] s = l.replaceAll("energy:", "").trim().split(" ");
        if (s.length != 2) throw new IOException("Parsing error: expected energy and its unit separated by a space");
        double value = Double.valueOf(s[0]);
        Energy.Unit unit;
        s[1] = s[1].trim();
        if (s[1].equals("MV")) unit = Energy.Unit.MV;
        else if (s[1].equals("MeV")) unit = Energy.Unit.MeV;
        else throw new IOException("Parsing error: encountered an unknown energy unit tag");
        tpr.setEnergy(new Energy(value, unit));
        // read the unit of the x parameters
        l = br.readLine();
        if (!l.startsWith("unit:")) throw new IOException("Parsing error: expected unit tag");
        l = l.replace("unit:", "").trim();
        Length.Unit lunit;
        if (l.equals("mm")) lunit = Length.Unit.mm;
        else if (l.equals("cm")) lunit = Length.Unit.cm;
        else throw new IOException("Parsing error: encountered an unknown unit tag");
        // equivalent field size
        l = br.readLine();
        if (!l.startsWith("equivalent field size:"))
            throw new IOException("Parsing error: expected equivalent field size tag");
        l = l.replaceAll("equivalent field size:", "").trim();
        tpr.setEquivalentFieldSize(new Length(Double.valueOf(l), lunit));
        // reference depth:
        l = br.readLine();
        if (!l.startsWith("reference depth:")) throw new IOException("Parsing error: expected reference depth tag");
        l = l.replaceAll("reference depth:", "").trim();
        tpr.setReferenceDepth(new Length(Double.valueOf(l), lunit));
        return lunit;
    }
}
